package com.ruoyi.web.controller.system;

import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysMenuService;

/**
 * 登录验证
 * 
 * @author ruoyi
 */
@RestController
public class SysLoginController
{
    private static final Logger log = LoggerFactory.getLogger(SysLoginController.class);

    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisCache redisCache;

    /**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    /**
     * 发送手机验证码
     * 
     * @param phoneNumber 手机号码
     * @param message 验证码消息内容
     * @return 结果
     */
    @PostMapping("/sendSmsCode")
    public AjaxResult sendSmsCode(@RequestParam String phoneNumber, @RequestParam(required = false) String message)
    {
        try
        {
            // 验证手机号格式
            if (StringUtils.isEmpty(phoneNumber) || !phoneNumber.matches("^1[3-9]\\d{9}$"))
            {
                return AjaxResult.error("请输入正确的手机号码");
            }

            // 检查是否在限制时间内重复发送
            String limitKey = "sms_limit:" + phoneNumber;
            if (redisCache.hasKey(limitKey))
            {
                return AjaxResult.error("验证码发送过于频繁，请60秒后再试");
            }

            // 生成6位数字验证码
            String verificationCode = generateVerificationCode();
            
            // 设置默认验证码消息
            if (StringUtils.isEmpty(message))
            {
                message = "您的验证码是：" + verificationCode + "，请在5分钟内使用。";
            }

            // 准备请求参数
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            params.add("post_tel", phoneNumber);
            params.add("post_msg", message);
            params.add("post_nma", "chilaoshu");

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

            // 创建请求实体
            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);

            // 发送POST请求
            String url = "http://60.164.231.180:3000/Service.lzww.php";
            ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);

            // 记录接口返回结果日志
            log.info("短信验证码接口调用结果 - 手机号: {}, 状态码: {}, 响应内容: {}", 
                    phoneNumber, response.getStatusCode(), response.getBody());

            // 判断返回结果是否包含23位字符串，如果是则表示成功
            String responseBody = response.getBody();
            boolean isSuccess = false;
            String extractedId = null;
            
            if (responseBody != null)
            {
                // 使用正则表达式提取23位数字字符串
                java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\"(\\d{23})\"");
                java.util.regex.Matcher matcher = pattern.matcher(responseBody);
                
                if (matcher.find())
                {
                    extractedId = matcher.group(1);
                    isSuccess = true;
                }
                else
                {
                    // 如果没有找到引号包围的23位数字，尝试直接查找23位连续数字
                    pattern = java.util.regex.Pattern.compile("(\\d{23})");
                    matcher = pattern.matcher(responseBody);
                    if (matcher.find())
                    {
                        extractedId = matcher.group(1);
                        isSuccess = true;
                    }
                }
            }
            
            if (isSuccess && extractedId != null)
            {
                // 短信发送成功，将验证码存储到Redis中，设置5分钟过期时间
                String cacheKey = "sms_code:" + phoneNumber;
                redisCache.setCacheObject(cacheKey, verificationCode, 5, TimeUnit.MINUTES);
                
                // 设置发送限制，60秒内不能重复发送
                redisCache.setCacheObject(limitKey, "1", 60, TimeUnit.SECONDS);
                
                log.info("短信验证码发送成功 - 手机号: {}, 验证码: {}, 短信ID: {}", 
                        phoneNumber, verificationCode, extractedId);
                return AjaxResult.success("验证码发送成功");
            }
            else
            {
                log.warn("短信验证码发送失败 - 手机号: {}, 状态码: {}, 返回内容: {}", 
                        phoneNumber, response.getStatusCode(), responseBody);
                return AjaxResult.error("验证码发送失败，请稍后重试");
            }
        }
        catch (Exception e)
        {
            log.error("短信验证码发送异常 - 手机号: {}, 异常信息: {}", phoneNumber, e.getMessage(), e);
            return AjaxResult.error("验证码发送异常：" + e.getMessage());
        }
    }

    /**
     * 验证短信验证码
     * 
     * @param phoneNumber 手机号码
     * @param code 验证码
     * @return 结果
     */
    @PostMapping("/verifySmsCode")
    public AjaxResult verifySmsCode(@RequestParam String phoneNumber, @RequestParam String code)
    {
        try
        {
            // 验证手机号格式
            if (StringUtils.isEmpty(phoneNumber) || !phoneNumber.matches("^1[3-9]\\d{9}$"))
            {
                return AjaxResult.error("请输入正确的手机号码");
            }

            // 验证验证码格式
            if (StringUtils.isEmpty(code) || !code.matches("^\\d{6}$"))
            {
                return AjaxResult.error("请输入6位数字验证码");
            }

            // 从Redis中获取验证码
            String cacheKey = "sms_code:" + phoneNumber;
            String cachedCode = redisCache.getCacheObject(cacheKey);

            if (StringUtils.isEmpty(cachedCode))
            {
                log.warn("验证码验证失败 - 手机号: {}, 原因: 验证码已过期或不存在", phoneNumber);
                return AjaxResult.error("验证码已过期或不存在，请重新获取");
            }

            // 验证验证码是否正确
            if (!code.equals(cachedCode))
            {
                log.warn("验证码验证失败 - 手机号: {}, 输入验证码: {}, 正确验证码: {}", 
                        phoneNumber, code, cachedCode);
                return AjaxResult.error("验证码错误，请重新输入");
            }

            // 验证成功，删除Redis中的验证码
            redisCache.deleteObject(cacheKey);
            
            log.info("验证码验证成功 - 手机号: {}", phoneNumber);
            return AjaxResult.success("验证码验证成功");
        }
        catch (Exception e)
        {
            log.error("验证码验证异常 - 手机号: {}, 异常信息: {}", phoneNumber, e.getMessage(), e);
            return AjaxResult.error("验证码验证异常：" + e.getMessage());
        }
    }

    /**
     * 手机验证码登录
     * 
     * @param phoneNumber 手机号码
     * @param code 验证码
     * @return 结果
     */
    @PostMapping("/smsLogin")
    public AjaxResult smsLogin(@RequestParam String phoneNumber, @RequestParam String code)
    {
        try
        {
            // 验证手机号格式
            if (StringUtils.isEmpty(phoneNumber) || !phoneNumber.matches("^1[3-9]\\d{9}$"))
            {
                return AjaxResult.error("请输入正确的手机号码");
            }

            // 验证验证码格式
            if (StringUtils.isEmpty(code) || !code.matches("^\\d{6}$"))
            {
                return AjaxResult.error("请输入6位数字验证码");
            }

            // 从Redis中获取验证码
            String cacheKey = "sms_code:" + phoneNumber;
            String cachedCode = redisCache.getCacheObject(cacheKey);

            if (StringUtils.isEmpty(cachedCode))
            {
                log.warn("手机验证码登录失败 - 手机号: {}, 原因: 验证码已过期或不存在", phoneNumber);
                return AjaxResult.error("验证码已过期或不存在，请重新获取");
            }

            // 验证验证码是否正确
            if (!code.equals(cachedCode))
            {
                log.warn("手机验证码登录失败 - 手机号: {}, 输入验证码: {}, 正确验证码: {}", 
                        phoneNumber, code, cachedCode);
                return AjaxResult.error("验证码错误，请重新输入");
            }

            // 验证成功，删除Redis中的验证码
            redisCache.deleteObject(cacheKey);
            
            // 根据手机号查找用户
            SysUser user = loginService.selectUserByPhoneNumber(phoneNumber);
            if (user == null)
            {
                log.warn("手机验证码登录失败 - 手机号: {}, 原因: 用户不存在", phoneNumber);
                return AjaxResult.error("该手机号未绑定用户，请联系管理员");
            }

            // 检查用户状态
            if (UserConstants.USER_DISABLE.equals(user.getStatus()))
            {
                log.warn("手机验证码登录失败 - 手机号: {}, 原因: 用户已停用", phoneNumber);
                return AjaxResult.error("用户已停用，请联系管理员");
            }

            // 创建登录用户对象
            LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, 
                    permissionService.getMenuPermission(user));
            
            // 记录登录信息
            loginService.recordLoginInfo(user.getUserId());
            
            // 生成token
            String token = tokenService.createToken(loginUser);
            
            log.info("手机验证码登录成功 - 手机号: {}, 用户名: {}", phoneNumber, user.getUserName());
            
            AjaxResult ajax = AjaxResult.success("登录成功");
            ajax.put(Constants.TOKEN, token);
            ajax.put("deptId", user.getDeptId());
            return ajax;
        }
        catch (Exception e)
        {
            log.error("手机验证码登录异常 - 手机号: {}, 异常信息: {}", phoneNumber, e.getMessage(), e);
            return AjaxResult.error("登录异常：" + e.getMessage());
        }
    }

    /**
     * 生成6位数字验证码
     * 
     * @return 验证码
     */
    private String generateVerificationCode()
    {
        return String.valueOf((int)((Math.random() * 9 + 1) * 100000));
    }

    /**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }

    /**
     * 获取路由信息
     * 
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }
    
    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate)
    {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0)
        {
            if (StringUtils.isNull(pwdUpdateDate))
            {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }
}
